<?php

namespace app\service;


use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;
use WeChatPay\Formatter;
use WeChatPay\Crypto\AesGcm;

class WechatPaymentService
{

    protected $instance;

    protected $merchantId = '1727084879';
    protected $appid = 'wx368e5e93edc15abb';
    protected $merchantCertificateSerial =   '7F65C3F94CD67B822F9BEB80A53BEAFE4A2A8EB0';
    protected $v3Key='2WGKMnmr28GQxAzRdaaKmTB8dMD8ZtQp';
    protected  $merchantPrivateKeyInstance;
    protected $onePlatformPublicKeyInstance;
    public function __construct()
    {
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        // 在项目目录下的cert目录
        $merchantPrivateKeyFilePath = root_path() . 'wechatpaycerts/apiclient_key.pem';
        $this->merchantPrivateKeyInstance = PemUtil::loadPrivateKey($merchantPrivateKeyFilePath);
        // $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        // $merchantCertificateSerial = '7F65C3F94CD67B822F9BEB80A53BEAFE4A2A8EB0'; //'7F65C3F94CD67B822F9BEB80A53BEAFE4A2A8EB0'; // API证书不重置，商户证书序列号就是个常量
        // 「商户API证书」的「证书序列号」
        // 平台证书，可由下载器 `./bin/CertificateDownloader.php` 生成并假定保存为 `/path/to/wechatpay/cert.pem`
        $platformCertificateFilePath = root_path() . 'wechatpaycerts/wechatpay_6EE5.pem';
        // 加载平台证书
        // $platformCertificateSerial = '7F65C3F94CD67B822F9BEB80A53BEAFE4A2A8EB0';
        $this->onePlatformPublicKeyInstance = PemUtil::loadCertificate($platformCertificateFilePath);
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($this->onePlatformPublicKeyInstance);
        // 解析平台证书序列号
        // $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateInstance);
        $this->instance = Builder::factory([
            'mchid'      => $this->merchantId,
            'serial'     => $this->merchantCertificateSerial,
            'privateKey' => $this->merchantPrivateKeyInstance,
            'certs'      => [
                $platformCertificateSerial => $this->onePlatformPublicKeyInstance,
                // $platformPublicKeyId  => $twoPlatformPublicKeyInstance,
            ],
        ]);
    }
    public function pay($params)
    {

        try {
            $resp = $this->instance->v3->pay->transactions->jsapi->post([
                'json' => [
                    'appid' => $this->appid,
                    "mchid" => $this->merchantId,
                    "description" => $params['body'], //商品描述】
                    "out_trade_no" => $params['order_sn'], //商户订单号
                    // 2018-06-08T10:34:56+08:00这样格式
                    "time_expire" => date('Y-m-d\TH:i:s\Z', time() + 3600), //time_expire
                    "attach" => "", //attach
                    "notify_url" => 'http://574e7679.r6.cpolar.cn/api/wechat/pay/notify', //env('APP_URL') . '/api/wechat/pay/notify',
                    "goods_tag" => "",
                    "support_fapiao" => false,
                    "amount" => [
                        //单位为分，整型
                        "total" => $params['total_pay'] * 100,
                        "currency" => "CNY",
                    ],
                    "payer" => [
                        "openid" => $params['openid'],
                    ],
                    "detail" => [
                        "cost_price" => $params['total_amount'] * 100, //array_sum(array_column($params['goods_detail'], 'unit_price')),
                        // "invoice_id" => "",
                        "goods_detail" => $params['goods_detail'],
                    ],
                    "scene_info" => [
                        "payer_client_ip" => $params['client_ip'],
                        "device_id" => $this->merchantId,
                        "store_info" => [
                            "id" => (string)$params['store_id'],
                            "name" => $params['store_name'],
                            "area_code" => "",
                            "address" => ""
                        ]
                    ],
                    "settle_info" => [
                        "profit_sharing" => false
                    ]
                ]
            ]);
        } catch (\Exception $e) {
            trace('error', $e->getTraceAsString());
            throw new \Exception($e->getMessage());
        }
        $data = json_decode((string) $resp->getBody(), true);
        if (!isset($data['prepay_id'])) {
            throw new \Exception('prepay_id not found');
        }
        $params = [
            'appId'     => $this->appid,
            'timeStamp' => (string)Formatter::timestamp(),
            'nonceStr'  => Formatter::nonce(),
            'package'   => 'prepay_id=' . $data['prepay_id'],
        ];
        $params += ['paySign' => Rsa::sign(
            Formatter::joinedByLineFeed(...array_values($params)),
            $this->merchantPrivateKeyInstance
        ), 'signType' => 'RSA'];
        return json_encode($params);
    }

    // 解密回调
    public function decryptNotify($inBody, $inWechatpaySignature, $inWechatpayTimestamp, $inWechatpaySerial, $inWechatpayNonce)
    {
        // 检查通知时间偏移量，允许5分钟之内的偏移
        // $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
        // $verifiedStatus = Rsa::verify(
        //     // 构造验签名串
        //     Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
        //     $inWechatpaySignature,
        //     $this->onePlatformPublicKeyInstance
        // );
        // if ($timeOffsetStatus && $verifiedStatus) {
        //     $inBodyArray = (array)json_decode($inBody, true);
        //     ['resource' => [
        //         'ciphertext'      => $ciphertext,
        //         'nonce'           => $nonce,
        //         'associated_data' => $aad
        //     ]] = $inBodyArray;
        //     $inBodyResource = AesGcm::decrypt($ciphertext, 'i5DRzeF3PmnYKQj3MjSEsJHQ3HaBzhPk', $nonce, $aad);
        //     $inBodyResourceArray = (array)json_decode($inBodyResource, true);
        //     return $inBodyResourceArray;
        // }
        // return false;
        // 获取解密所需的参数
        $algorithm = $inBody['algorithm']; // 加密算法
        $ciphertext = $inBody['ciphertext']; // 密文
        $associatedData = $inBody['associated_data']; // 关联数据
        $nonce = $inBody['nonce']; // 随机数
        $aesGcm = new AesGcm();
        // 解密数据
        $decryptedData = $aesGcm::decrypt($ciphertext, $this->v3Key, $nonce, $associatedData);

        // 解析解密后的 JSON 数据
        $decryptedData = json_decode($decryptedData, true);

        return $decryptedData;
    }
}
